/*
* Copyright (C) 2020 ~ 2024 chaigec All Rights Reserved.
*
* Author:     chaigec <chaigec@163.com>
* Maintainer: chaigec <chaigec@163.com>

 * Use of this source code is governed by MIT license that can be found in the
 * LICENSE file in the root of the source tree. All contributing project authors
 * may be found in the AUTHORS file in the root of the source tree.
*/

#include "MkHttpUri.h"
#include "MkUtil/MkUtil.h"
#include "MkUtil/MkLog.h"

static const Uint8 UriChars[256] = {
    /* 0 */
    0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 1, 1, 0,
    1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 0, 0, 0, 0, 0, 0,
    /* 64 */
    0, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,
    1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 0, 0, 0, 0, 1,
    0, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,
    1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 0, 0, 0, 1, 0,
    /* 128 */
    0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,
    /* 192 */
    0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,
};

static const Uint32 IsXdigit[8] =
{ 0, 0x3ff0000, 0x7e, 0x7e, 0, 0, 0, 0 };

CMkHttpUri::CMkHttpUri()
{

}

Uint32 CMkHttpUri::ParseUri(const MkString& Uri)
{
    MkString DecUri;
    Uint32 ErrorCode = UriDecode(Uri, TRUE, DecUri);
    MkCheckErrorLog(ErrorCode, "decode uri:%s failed\n", Uri.c_str());
    MkVector<MkString> vecString;
    ErrorCode = CMkUtil::StringSplit(Uri, "?", vecString);
    MkCheckErrorLog(ErrorCode, "string:%s split ? failed\n", Uri.c_str());
    if (vecString.empty()) {
        return InvalidParams;
    }
    m_UriPath = vecString[0];
    if (vecString.size() > 1)  // has params
    {
        MkVector<MkString> vecParams;
        ErrorCode = CMkUtil::StringSplit(vecString[1], "&", vecParams);
        MkCheckErrorLog(ErrorCode, "string:%s split & failed\n", vecString[1].c_str());
        MkVector<MkString> vecParam;
        for (size_t i = 0; i < vecParams.size(); i++) {
            vecParam.clear();
            CMkUtil::StringSplit(vecParams[i], "=", vecParam);
            if (vecParam.size() >= 2) {
                AddParam(vecParam[0], vecParam[1]);
            }
        }
    }
    return NoneError;
}

Uint32 CMkHttpUri::AddParam(const MkString& Key, const MkString& Value)
{
    m_Params[Key] = Value;
    return NoneError;
}

Uint32 CMkHttpUri::SetUriPath(const MkString& UriPath)
{
    m_UriPath = UriPath;
    return NoneError;
}

Uint32 CMkHttpUri::ToString(MkString& strUri)
{
    strUri.clear();
    MkString TmpUri = "";
    if (!m_Params.empty()) {
        TmpUri += "?";
        MkMapString::iterator it = m_Params.begin();
        MkMapString::iterator itLast = --m_Params.end();
        for (; it != m_Params.end(); it++) {
            TmpUri += it->first + "=" + it->second;
            if (it != itLast) {
                TmpUri += "&";
            }
        }
    }
    //Uint32 ErroCode = UriEncode(TmpUri, TRUE, strUri);
    //MkCheckErrorLog(ErroCode, "uri encode failed\n");
    strUri = m_UriPath + TmpUri;
    return NoneError;
}

void CMkHttpUri::Release()
{
    m_UriPath.clear();
    m_Params.clear();
}

Uint32 CMkHttpUri::UriEncode(const MkString& Uri, BOOL SpaceAsPlus, MkString& EncodeUri)
{
    EncodeUri.clear();
    char pTmp[Len16] = { 0 };
    for (size_t i = 0; i < Uri.size(); i++) {
        if (UriChars[(Uint8)Uri[i]]) {
            EncodeUri += Uri[i];
        } else if (' ' == Uri[i] && SpaceAsPlus) {
            EncodeUri += '+';
        } else {
            snprintf(pTmp, Len16, "%%%02X", (Uint8)Uri[i]);
            EncodeUri += pTmp;
        }
    }
    EncodeUri += "";
    return NoneError;
}

Uint32 CMkHttpUri::UriDecode(const MkString& Uri, BOOL DecodePlus, MkString& DecodeUri)
{
    DecodeUri.clear();
    for (size_t i = 0; i < Uri.size(); i++) {
        if ('+' == Uri[i] && DecodePlus) {
            DecodeUri += ' ';
        } else if ((i + 2) < Uri.size()
            && '%' == Uri[i]
            && CMkUtil::IsHex((Uint8)Uri[i + 1])
            && CMkUtil::IsHex((Uint8)Uri[i + 2])) {
            char Tmp[3] = { 0 };
            Tmp[0] = Uri[i + 1];
            Tmp[1] = Uri[i + 2];
            DecodeUri += (char)strtol(Tmp, nullptr, 16);
            i += 2;
        } else {
            DecodeUri += Uri[i];
        }
    }
    DecodeUri += "";
    return NoneError;
}

CMkHttpUri::~CMkHttpUri()
{

}